﻿/**@author W意波 编写*/
#ifndef LK_TIME_
#define LK_TIME_
namespace LK
{
	/**
	@brief Time类表示时间长度
	@note 当把Time对象视为时刻时，其保存的是公元元年到该时刻的时间长度*/
	struct Time :virtual Object, virtual ICloneables
	{
	protected:
		/**
		@brief 获取公元元年至指定年月日总天数
		@param [传入]参数year表示指定的年份
		@param [传入]参数month表示指定的月份
		@param [传入]参数day表示指定的日
		@return 返回度过的天数*/
		static double GetDays(double year, unsigned int month, unsigned int day);
		/**
		@brief 根据年份和当年已过天数获取月份，输入的天数将变为日输出
		@param [传入]参数year用以指定年份
		@param [传入,写出]参数days用以传入已过天数和输出结果日
		@return 返回月份*/
		static unsigned int GetMonthByDaysInYear(double year, unsigned int& days);
		/**
		@brief 设置当前的本地时刻
		@param [传入]参数now表示当前时刻，即公元元年元月1日0点到当前时刻的长度*/
		static void SetLocal(const ptr<Time>& now);
		/**
		@brief 同时获取该对象所表示时刻的年份和当年的已过天数
		@param [写出]参数pday用以输出该时间对应日期在当年已过天数
		@return 返回该时间所在年份
		@note 该函数认为该对象表示时刻*/
		double GetYearAndDaysInYear(unsigned int*pday)const;
	public:
		/**@brief 通用基类方法*/
		BMETHODS(ptr<Time>, Time)
		/**@brief 交换*/
		void SwapWith(Time& x) { Swap(time, x.time); }
		/**@brief 产生一个浅表副本*/
		Time* Clone()const { return new Time(*this); }
		/**
		@brief 获取当前的本地时刻*/
		static ptr<Time> GetLocal();
		static double GetLocalSeconds();
#ifdef _WINDOWS
		/**@brief 获取CPU时钟*/
		static inline LARGE_INTEGER& CpuCounterReference()
		{
			static LARGE_INTEGER f = { 0 };
			QueryPerformanceCounter(&f);
			return f;
		}
#endif
		/**
		@brief 每微秒的时长*/
		const static double EveryMicrosecond;
		/**
		@brief 每毫秒时间长度*/
		const static double EveryMillisecond;
		/**
		@brief 每秒时间长度*/
		const static double EverySecond;
		/**
		@brief 每分时间长度*/
		const static double EveryMinute;
		/**
		@brief 每小时时间长度*/
		const static double EveryHour;
		/**
		@brief 每天时间长度*/
		const static double EveryDay;
		/**
		@brief 每周时间长度*/
		const static double EveryWeek;
		/**
		@brief 获取该时间所在年份
		@note 该函数认为该对象表示时刻*/
		double GetYear()const;
		/**
		@brief 获取该时间所在月份
		@note 该函数认为该对象表示时刻*/
		unsigned int GetMonth()const;
		/**
		@brief 获取该时间所在日
		@note 该函数认为该对象表示时刻*/
		unsigned int GetDay()const;
		/**
		@brief 获取该时间表示星期几（0代表星期天）
		@note 该函数认为该对象表示时刻*/
		unsigned int GetDayOfWeek()const;
		/**
		@brief 获取时
		@note 该函数认为该对象表示时刻*/
		unsigned int GetHour()const;
		/**
		@brief 获取分
		@note 该函数认为该对象表示时刻*/
		unsigned int GetMinute()const;
		/**
		@brief 获取秒
		@note 该函数认为该对象表示时刻*/
		unsigned int GetSecond()const;
		/**
		@brief 获取毫秒
		@note 该函数认为该对象表示时刻*/
		unsigned int GetMillisecond()const;
		/**
		@brief 获取微秒
		@note 该函数认为该对象表示时刻*/
		unsigned int GetMicrosecond()const;
		/**
		@brief 设置年
		@note 该函数认为该对象表示时刻*/
		void SetYear(double);
		/**
		@brief 设置月
		@note 该函数认为该对象表示时刻*/
		void SetMonth(unsigned int);
		/**
		@brief 设置日
		@note 该函数认为该对象表示时刻*/
		void SetDay(unsigned int);
		/**
		@brief 设置时
		@note 该函数认为该对象表示时刻*/
		void SetHour(unsigned int);
		/**
		@brief 设置分
		@note 该函数认为该对象表示时刻*/
		void SetMinute(unsigned int);
		/**
		@brief 设置秒
		@note 该函数认为该对象表示时刻*/
		void SetSecond(unsigned int);
		/**
		@brief 设置毫秒
		@note 该函数认为该对象表示时刻*/
		void SetMillisecond(unsigned int);
		/**
		@brief 设置微秒
		@note 该函数认为该对象表示时刻*/
		void SetMicrosecond(unsigned int);
		/**
		@brief 使用一个双精度浮点来记录时间，单位秒*/
		double time;
		/**
		@brief 默认构造函数*/
		Time();
		/**
		@brief 从字符串构造*/
		Time(const ptr<String>&str);
		/**@brief 使用一个浮点数来初始化*/
		Time(double t);
#ifdef _WINDOWS
		/**
		@brief 使用一个WindowsAPI定义的系统时间来初始化*/
		Time(const ::SYSTEMTIME& t);
#endif
		/**
		@brief 使用一个标准库定义的系统时间来初始化*/
		Time(const ::tm& t);
		/**
		@brief 属性：当前时间*/
		static StaticProperty<ptr<Time>> Now;
		/**
		@brief 获取该对象所示时长（取整到天数，可能为负）*/
		double GetDays()const;
		/**
		@brief 获取该对象所示时长（取整到小时数，可能为负）*/
		double GetHours()const;
		/**
		@brief 获取该对象所示时长（取整到分数，可能为负）*/
		double GetMinutes()const;
		/**
		@brief 获取该对象所示时长（取整到秒数，可能为负）*/
		double GetSeconds()const;
		/**
		@brief 获取该对象所示时长（取整到毫秒数，可能为负）*/
		double GetMilliseconds()const;
		/**
		@brief 获取该对象所示时长（取整到微秒数，可能为负）*/
		double GetMicroseconds()const;
		/**
		@brief 取时长，按秒为单位*/
		operator double()const;
#ifdef _WINDOWS
		/**
		@brief 转换为WindowsAPI的系统时间*/
		operator ::SYSTEMTIME()const;
#endif
		/**
		@brief 转换为stl中的日期*/
		operator ::tm()const;

		/**@brief 重载算数运算符*/
		Time&operator+=(double t) { time += t; return *this; }
		/**@brief 重载算数运算符*/
		Time&operator-=(double t) { time -= t; return *this; }
		/**@brief 重载算数运算符*/
		Time&operator%=(double t) { time =fmod(time, t); return *this; }
		/**@brief 重载算数运算符*/
		Time&operator*=(double t) { time *= t; return *this; }
		/**@brief 重载算数运算符*/
		Time&operator/=(double t) { time /= t; return *this; }
		/**@brief 重载算数运算符*/
		Time friend operator+(const Time& t1, const Time& t2) { return Time(t1.time + t2.time); }
		/**@brief 重载算数运算符*/
		Time friend operator-(const Time& t1, const Time& t2) { return Time(t1.time - t2.time); }

		/**@brief 赋值运算*/
		Time& operator=(const Time& t);
		/**@brief 赋值运算*/
		Time& operator=(double t);

		/**
		@brief 线程挂起一段时间
		@param [传入]参数t表示间隔时间长度
		@note 与Sleep不同，该方法相当于定时器，意为每隔时间t就放行一次，内部使用Sleep实现*/
		void Wait(const Time& t);

		/**
		@brief 表示空时间*/
		static ptr<Time> const& GetEmptyRef();
		/**
		@brief 到字符串的转换（时间长度），重写XBase::ToString()*/
		virtual ptr<String> ToString()const;
		/**
		@brief 到字符串的转换（格式化输出）
		@param [传入]参数str用以指定输出格式*/
		ptr<String> ToString(const ptr<String>&str)const;
		/**
		@brif 添加类型信息*/
		static void AddTypeInfo();
#ifdef _CLR /**@brief 托管支持*/
		/**
		@brief 从托管的时间构造*/
		Time(System::DateTime^time);
		/**
		@brief 转换到托管的时间*/
		System::DateTime^ ToDateTime()const;
#endif
	};
	template<>struct ptr<Time> : ptr<ICloneables>
	{
	public:
		PMETHODS(ptr, Time);
		/**@brief 从字符串构造*/
		ptr(const ptr<String>&str);
		/**@brief 使用一个整数值来初始化*/
		ptr(double t) :ptr<ICloneables>(new Time(t)) {}
#ifdef _WINDOWS
		/**@brief 使用一个WindowsAPI定义的系统时间来初始化*/
		ptr(const ::SYSTEMTIME& t) : ptr<ICloneables>(new Time(t)) {}
#endif
		/**@brief 使用一个标准库定义的系统时间来初始化*/
		ptr(const ::tm& t) : ptr<ICloneables>(new Time(t)) {}
		/**@brief 取时长，按秒为单位（相对公元元年）*/
		operator double()const { return *Check(); }
#ifdef _WINDOWS
		/**@brief 转换为WindowsAPI的系统时间*/
		operator ::SYSTEMTIME()const { return *Check(); }
#endif
		/**@brief 转换为标准库的系统时间*/
		operator ::tm()const { return *Check(); }
		/**@brief 重载算数运算符*/
		ptr<Time>&operator+=(double t) { Convert<ptr, PObject>::RefFrom(ICloneables::OnePtr(*this))->time += t; return *this; }
		/**@brief 重载算数运算符*/
		ptr<Time>&operator-=(double t) { Convert<ptr, PObject>::RefFrom(ICloneables::OnePtr(*this))->time -= t;  return *this; }
		/**@brief 重载算数运算符*/
		ptr<Time>&operator%=(double t) { Convert<ptr, PObject>::RefFrom(ICloneables::OnePtr(*this))->time = fmod(Convert<ptr, PObject>::RefFrom(ICloneables::OnePtr(*this))->time, t); return *this; }
		/**@brief 重载算数运算符*/
		ptr<Time>&operator*=(double t) { Convert<ptr, PObject>::RefFrom(ICloneables::OnePtr(*this))->time *= t; return *this; }
		/**@brief 重载算数运算符*/
		ptr<Time>&operator/=(double t) { Convert<ptr, PObject>::RefFrom(ICloneables::OnePtr(*this))->time /= t; return *this; }
		/**@brief 重载算数运算符*/
		friend inline ptr<Time> operator+(const ptr<Time> t1, const ptr<Time> t2) { return ptr<Time>(t1.Check()->time + t2.Check()->time); }
		/**@brief 重载算数运算符*/
		friend inline ptr<Time> operator-(const ptr<Time> t1, const ptr<Time> t2) { return ptr<Time>(t1.Check()->time - t2.Check()->time); }

		/**@brief 赋值运算*/
		ptr<Time>& operator=(double t) { Convert<ptr, PObject>::RefFrom(ICloneables::OnePtr(*this))->time = t; return *this; }
		
		/**
		@brief 线程挂起一段时间(写时复制)
		@param [传入]参数t表示间隔时间
		@note 与Sleep不同，该方法相当于定时器，意为每隔时间t就放行一次，内部使用Sleep实现*/
		void Wait(const ptr& t) { Convert<ptr, PObject>::RefFrom(ICloneables::OnePtr(*this))->Wait(*t.Check()); }


#ifdef _CLR /**@brief 托管支持*/
		/**@brief 从托管的时间转换*/
		ptr(System::DateTime^time) :ptr<Object>(new Time(time)) {}
		/**@brief 转换到托管的时间*/
		System::DateTime^ ToDateTime()const { return Check()->ToDateTime(); }
#endif
	};
	typedef ptr<Time> PTime;
}
#endif
